[주의!] 문서의 이전 버전(에 수정)을 보고 있습니다. 최신 버전으로 이동



Fibonacci Lucky Numbers
파일:boj-favicon.png
문제 번호
32454
기여자
레이팅
파일:solvedac-tier-19.svg Platinum II
알고리즘
More
수학
정수론
분할 정복을 이용한 거듭제곱
오일러 피 함수
피사노 주기

1. 개요2. 풀이3. 정답 코드
3.1. C++

1. 개요 [편집]

To claim the jackpot, you need to compute the last 1010 digits of the F777nF_{7^{7^{7^n}}}, the 777n7^{7^{7^n}}-th Fibonacci number.
피보나치 수열의 777n7^{7^{7^n}}번째 수의 마지막 10번째 자리까지 출력하면 되는 문제다.

2. 풀이 [편집]

당연히 쌩으로 구하기에는 매우 큰 수이다. 마지막 10번째 자리까지 출력하기 위해서는 101010^{10}로 나눈 나머지를 구하면 된다. 또한 피보나치 수에서 나누는 값이 22보다 큰 mm에 대하여 10m10^{m}라면 주기는 15×10m115 \times 10^{m-1}인 피사노 주기를 이용할 수 있다. 여기서 m=10m=10이므로 777n(mod 15×109){7^{7^{7^n}}} (\bmod \ 15 \times 10^{9})번째 피보나치 수를 101010^{10}으로 나눈 나머지를 구하는 문제로 환원된다.

777n(mod15×109){7^{7^{7^n}}} (\bmod 15 \times 10^{9})를 구하기 위해서는 오일러 공식을 활용하여 풀 수 있다.
m0=15×109,m1=φ(m0),m2=φ(m1)m_0 = 15 \times 10^{9}, \quad m_1 = \varphi(m_0), \quad m_2 = \varphi(m_1)
라고 하자. m1m_1m2m_2 모두 7과 서로소이므로 다음과 같다.
e1(n)=7nmodm2(modm2)e_1(n) = 7^{\,n \bmod m_2} \pmod{m_2}
e2(n)=7e1(n)modm1(modm1)e_2(n) = 7^{\,e_1(n) \bmod m_1} \pmod{m_1}
e3(n)=7e2(n)modm0(modm0)e_3(n) = 7^{\,e_2(n) \bmod m_0} \pmod{m_0}
777nmodm0=e3(n)7^{7^{7^n}} \bmod m_0 = e_3(n)

e3(n)e_3(n)을 구한 후, e3(n)e_3(n)번째 피보나치 수를 구하면 된다. 이 값은 15×10915 \times 10^{9}보다 작으므로 피보나치 수를 O(logn)\mathcal{O(\log n)} 방법으로 구하면 된다.

3. 정답 코드 [편집]

3.1. C++ [편집]

코드 보기/접기
#include <bits/stdc++.h>

#define fastio cin.tie(0), ios_base::sync_with_stdio(false)
using i64 = long long;
using u128 = unsigned __int128;
using namespace std;
i64 mod = (i64)1e10;

vector<vector<i64>> calc(const vector<vector<i64>>& m1, const vector<vector<i64>>& m2) {
    vector<vector<i64>> matrix(2, vector<i64>(2, 0));
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 2; ++j) {
            u128 val = 0;
            for (int k = 0; k < 2; ++k) {
                val += (u128)m1[i][k] * (u128)m2[k][j];
            }
            matrix[i][j] = (i64)(val % (u128)mod);
        }
    }
    return matrix;
}

vector<vector<i64>> func(vector<vector<i64>> mat, i64 n) {
    vector<vector<i64>> res = {{1, 0}, {0, 1}};
    while (n > 0) {
        if (n & 1) res = calc(res, mat);
        mat = calc(mat, mat);
        n >>= 1;
    }
    return res;
}

i64 powmod(i64 a, i64 e, i64 m) {
    u128 A = (a % m + m) % m;
    u128 M = m;
    u128 r = 1;
    while (e > 0) {
        if (e & 1) r = (r * A) % M;
        A = (A * A) % M;
        e >>= 1;
    }
    return (i64)r;
}

int main() {
    fastio;
    int t;
    cin >> t;
    while (t--) {
        i64 n;
        cin >> n;

        vector<vector<i64>> matrix = {{1, 1}, {1, 0}};
        i64 e1 = powmod(7, n, 16LL*(i64)1e7);      // 160,000,000
        i64 e2 = powmod(7, e1, 4LL*(i64)1e8);      // 400,000,000
        i64 e3 = powmod(7, e2, 15LL*(i64)1e9);     // 15,000,000,000

        string rans;
        if (e3 <= 1) rans = string(9,'0') + char('0'+(int)e3);
        else {
            auto M = func(matrix, e3-1);
            i64 val = M[0][0] % mod;
            rans = to_string(val);
            if ((int)rans.size()<10) rans = string(10-rans.size(), '0')+rans;
        }
        cout << rans << '\n';
    }
    return 0;
}